package com.tengju.user.application.club;

import com.tengju.user.application.club.dto.ClubAddDTO;
import com.tengju.user.application.club.dto.ClubAddMemberDTO;
import com.tengju.user.application.club.dto.ClubUpdateDTO;
import com.tengju.user.application.club.dto.UserChangeClubDTO;
import com.tengju.user.domain.model.club.*;
import com.tengju.user.domain.model.user.*;
import com.tengju.user.domain.service.UserDocService;
import com.tengju.user.domain.shared.JsonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author chenhang
 * @Date 2021/1/13
 */
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class ClubManageService {

    private final ClubRepository clubRepository;
    private final ClubMemberRepository clubMemberRepository;
    private final ClubZoneRelationRepository clubZoneRelationRepository;
    private final UserInfoRepository userInfoRepository;
    private final ZoneRepository zoneRepository;
    private final UserDocService userDocService;

    @Transactional(value = "dealerTransactionManager", rollbackFor = Exception.class)
    public void add(ClubAddDTO clubAddDTO, Staff staff) {
        String clubName = clubAddDTO.getClubName();
        String clubHeadImg = clubAddDTO.getClubHeadImg();
        UserIdCode founderIdCode = UserIdCode.of(clubAddDTO.getFounderIdCode());
        UserId founderUserId = null;
        List<Long> memberIdCodes = clubAddDTO.getMemberIdCodes().stream().distinct().collect(Collectors.toList());
        Club club = clubRepository.findByName(clubName);
        if (club != null) {
            throw new ClubException("俱乐部名称已经被使用，name: " + clubName);
        }
        if (!memberIdCodes.contains(founderIdCode.getValue())) {
            throw new ClubException("俱乐部创始人必须在俱乐部名单内");
        }
        List<UserInfo> members = new ArrayList();
        for (Long memberIdCode : memberIdCodes) {
            UserInfo userInfo = userInfoRepository.getByIdCode(UserIdCode.of(memberIdCode));
            if (userInfo == null) {
                throw new ClubException("俱乐部成员不存在，成员: " + memberIdCode);
            }
            StarLevelEnum starLevel = StarLevelEnum.parseByCode(userInfo.getStarLevel());
            if (starLevel == null || !starLevel.isHigher(StarLevelEnum.EC)) {
                throw new ClubException("俱乐部成员必须为SEC、EEC，成员: " + memberIdCode);
            }
            ClubId memberClubId = clubMemberRepository.findClubIdByIdCode(userInfo.getIdCode());
            if (memberClubId != null ) {
                throw new ClubException(String.format("用户：%s,已经属于俱乐部：%s,请先删除再添加", memberIdCode,memberClubId.getValue()));
            }
            founderUserId = userInfo.getUserId();
            members.add(userInfo);
        }
        club = new Club(
                founderIdCode,
                founderUserId,
                clubName,
                clubHeadImg,
                staff.getName()
        );
        Zone zone = zoneRepository.findById(clubAddDTO.getZoneId());
        if (zone == null) {
            throw new ClubException("战区不存在："+ clubAddDTO.getZoneId());
        }
        ClubId clubId = clubRepository.save(club);
        clubMemberRepository.addClubMember(clubId,members);
        ClubZoneRelation clubZoneRelation = new ClubZoneRelation(
                clubId,
                new ZoneId(clubAddDTO.getZoneId()),
                staff.getName(),
                staff.getName()
        );
        clubZoneRelationRepository.save(clubZoneRelation);
    }

    @Transactional(value = "dealerTransactionManager", rollbackFor = Exception.class)
    public void updateClub(ClubUpdateDTO clubUpdateDTO, Staff staff) {
        ClubId clubId = new ClubId(clubUpdateDTO.getClubId());
        Club meta = clubRepository.findById(clubId);
        if (meta == null) {
            throw new ClubException("俱乐部不存在，id: " + clubId);
        }
        UserId founderUserId = meta.getFounderUserId();
        UserInfo founderUserInfo = userInfoRepository.getByIdCode(UserIdCode.of(clubUpdateDTO.getFounderIdCode()));
        if (founderUserInfo == null) {
            throw new ClubException("创始人不存在，成员: " + clubUpdateDTO.getFounderIdCode());
        }
        if (meta.getFounderIdCode() == null || meta.getFounderIdCode().getValue() != clubUpdateDTO.getFounderIdCode()) {
            StarLevelEnum starLevel = StarLevelEnum.parseByCode(founderUserInfo.getStarLevel());
            if (starLevel == null || !starLevel.isHigher(StarLevelEnum.EC)) {
                throw new ClubException("俱乐部创始人必须为SEC、EEC，创始人: " + clubUpdateDTO.getFounderIdCode());
            }
            founderUserId = founderUserInfo.getUserId();
        }
        ClubId founderClubId = clubMemberRepository.findClubIdByIdCode(UserIdCode.of(clubUpdateDTO.getFounderIdCode()));
        if (founderClubId != null && !founderClubId.equals(clubId)) {
            throw new ClubException(String.format("创始人：%s,已经属于俱乐部：%s,请先删除再添加", clubUpdateDTO.getFounderIdCode(),founderClubId.getValue()));
        }
        if (!meta.getClubName().equals(clubUpdateDTO.getClubName())) {
            Club club = clubRepository.findByName(clubUpdateDTO.getClubName());
            if (club != null) {
                throw new ClubException("俱乐部名称已经被使用，name: " + clubUpdateDTO.getClubName());
            }
        }
        Map<ClubId, List<Long>> clubIdMemberMap = clubMemberRepository.batchGetMembers(List.of(clubId));
        List<Long> members = clubIdMemberMap.get(clubId);
        if (CollectionUtils.isEmpty(members) || !members.contains(clubUpdateDTO.getFounderIdCode())) {
            clubMemberRepository.addClubMember(clubId,List.of(founderUserInfo));
        }
        meta.update(UserIdCode.of(clubUpdateDTO.getFounderIdCode()),
                founderUserId,
                clubUpdateDTO.getClubName(),
                clubUpdateDTO.getClubHeadImg(),
                staff.getName()
                );
        clubRepository.update(meta);
        ClubZoneRelation clubZoneRelation = clubZoneRelationRepository.findByClubId(clubId);
        if (clubZoneRelation == null) {
            throw new ClubException(String.format("俱乐部关系不存在，clubId: %s", clubId));
        }
        Zone zone = zoneRepository.findById(clubUpdateDTO.getZoneId());
        if (zone == null) {
            throw new ClubException("战区不存在："+ clubUpdateDTO.getZoneId());
        }
        ZoneId newZoneId = new ZoneId(clubUpdateDTO.getZoneId());
        if (clubZoneRelation.isSameZone(newZoneId)) {
            return;
        }
        clubZoneRelation.changeZoneId(newZoneId,staff);
        clubZoneRelationRepository.updateRelation(clubZoneRelation);
    }

    public void addClubMember(ClubAddMemberDTO clubAddMemberDTO) {
        ClubId clubId = new ClubId(clubAddMemberDTO.getClubId());
        Club meta = clubRepository.findById(clubId);
        if (meta == null) {
            throw new ClubException("俱乐部不存在，id: " + clubId);
        }
        List<Long> memberIdCodes = clubAddMemberDTO.getMemberIdCodes().stream().distinct().collect(Collectors.toList());
        List<UserInfo> members = new ArrayList();
        for (Long memberIdCode : memberIdCodes) {
            UserInfo userInfo = userInfoRepository.getByIdCode(UserIdCode.of(memberIdCode));
            if (userInfo == null) {
                throw new ClubException("俱乐部成员不存在，成员: " + memberIdCode);
            }
            StarLevelEnum starLevel = StarLevelEnum.parseByCode(userInfo.getStarLevel());
            if (starLevel == null || !starLevel.isHigher(StarLevelEnum.EC)) {
                throw new ClubException("俱乐部成员必须为SEC、EEC，成员: " + memberIdCode);
            }
            ClubId memberClubId = clubMemberRepository.findClubIdByIdCode(userInfo.getIdCode());
            if (memberClubId != null && !memberClubId.equals(clubId)) {
                throw new ClubException(String.format("用户：%s,已经属于俱乐部：%s", memberIdCode,memberClubId.getValue()));
            }
            if (memberClubId != null) {
                continue;
            }
            members.add(userInfo);
        }
        if (CollectionUtils.isEmpty(members)) {
            return;
        }
        clubMemberRepository.addClubMember(clubId,members);
        //如果俱乐部创始人为空，补充创始人
        Club club = clubRepository.findById(clubId);
        if (club.getFounderIdCode() != null) {
            return;
        }
        UserInfo founderUser = members.get(0);
        club.changeFounder(founderUser,ManageUser.getAdminManageUser().getRealName());
        clubRepository.update(club);
    }

    public void userChangeClub(UserChangeClubDTO userChangeClubDTO) {
        UserIdCode idCode = UserIdCode.of(userChangeClubDTO.getIdCode());
        ClubId newClubId = new ClubId(userChangeClubDTO.getNewClubId());
        ClubId memberClubId = clubMemberRepository.findClubIdByIdCode(idCode);
        if (memberClubId == null) {
            throw new ClubException(String.format("用户：%s,还未属于任何俱乐部", idCode.getValue()));
        }
        if (newClubId.equals(memberClubId)) {
            throw new ClubException(String.format("用户：%s,已经属于俱乐部：%s", idCode.getValue(),memberClubId.getValue()));
        }
        Club curClub = clubRepository.findById(memberClubId);
        if (idCode.equals(curClub.getFounderIdCode())) {
            throw new ClubException(String.format("用户：%s,属于俱乐部创始人，不能迁移俱乐部", idCode.getValue()));
        }
        Club newClub = clubRepository.findById(newClubId);
        if (newClub == null) {
            throw new ClubException("俱乐部不存在，id: " + newClubId.getValue());
        }
        clubMemberRepository.changeClub(idCode,newClubId);
        //如果俱乐部创始人为空，补充创始人
        if (newClub.getFounderIdCode() != null) {
            return;
        }
        UserInfo founderUser = userInfoRepository.getByIdCode(idCode);
        newClub.changeFounder(founderUser,ManageUser.getAdminManageUser().getRealName());
        clubRepository.update(newClub);
    }

    public void updateStarChange(StarChangeEvent event) {
        StarLevelEnum afterStarLevel = StarLevelEnum.parseByCode(event.getAfterStarLevel());
        StarLevelEnum beforeStarLevel = StarLevelEnum.parseByCode(event.getBeforeStarLevel());
        if (afterStarLevel == null || beforeStarLevel == null) {
            log.error("星级变更数据不完整:{}", JsonUtil.toJSONString(event));
            throw new ClubException("星级变更数据不完整");
        }
        boolean isMeetClub = afterStarLevel.isHigher(StarLevelEnum.EC) || beforeStarLevel.isHigher(StarLevelEnum.EC);
        if (!isMeetClub) {
            return;
        }
        boolean isRise = afterStarLevel.isHigher(beforeStarLevel);
        if (isRise) {
            userAddToClub(event.getIdCode());
        } else {
            //额外判断是是否级到sec以下
            if (!afterStarLevel.isHigher(StarLevelEnum.EC)) {
                userRemoveFromClub(event.getIdCode(),ManageUser.getAdminManageUser());
            }
        }
    }

    @Transactional(value = "dealerTransactionManager", rollbackFor = Exception.class)
    public void userRemoveFromClub(Long idCodeValue, ManageUser manageUser) {
        UserIdCode idCode = UserIdCode.of(idCodeValue);
        ClubId clubId = clubMemberRepository.findClubIdByIdCode(idCode);
        if (clubId == null) {
            log.info("用户:{},不属于任何俱乐部，不需要剔除",idCodeValue);
            return;
        }
        clubMemberRepository.removeMember(idCode,clubId);
        Club club = clubRepository.findById(clubId);
        if (!club.getFounderIdCode().equals(idCode)) {
            return;
        }
        log.info("用户:{},属于任何俱乐部:{} 创始人,随机选择其他成员成为创始人",idCodeValue,clubId.getValue());
        Map<ClubId, List<Long>> clubMemberMap = clubMemberRepository.batchGetMembers(List.of(clubId));
        if (CollectionUtils.isEmpty(clubMemberMap)) {
            club.removeFounder(manageUser.getRealName());
        } else {
            List<Long> members = clubMemberMap.get(clubId);
            UserIdCode newFounderIdCode = UserIdCode.of(members.get(0));
            UserInfo founderUserInfo = userInfoRepository.getByIdCode(newFounderIdCode);
            if (founderUserInfo == null) {
                throw new ClubException("俱乐部成员不存在，" + newFounderIdCode.getValue());
            }
            club.changeFounder(founderUserInfo,manageUser.getRealName());
        }
        clubRepository.update(club);
    }

    @Transactional(value = "dealerTransactionManager", rollbackFor = Exception.class)
    public void userAddToClub(Long idCodeValue) {
        UserIdCode idCode = UserIdCode.of(idCodeValue);
        ClubId clubId = clubMemberRepository.findClubIdByIdCode(idCode);
        if (clubId != null) {
            return;
        }
        clubId = findFirstClub(idCode,StarLevelEnum.SEC,StarLevelEnum.EEC);
        if (clubId == null) {
            throw new ClubException(String.format("用户 %s 上级关系链没有所属俱乐部", idCodeValue));
        }
        ClubAddMemberDTO clubAddMemberDTO = new ClubAddMemberDTO();
        clubAddMemberDTO.setClubId(clubId.getValue());
        clubAddMemberDTO.setMemberIdCodes(List.of(idCodeValue));
        addClubMember(clubAddMemberDTO);
    }

    private ClubId findFirstClub(UserIdCode idCode, StarLevelEnum sec, StarLevelEnum eec) {
        UserInfo superiorUser = findSuperiorUserOr(idCode, sec, eec);
        if (superiorUser == null) {
            return null;
        }
        ClubId clubId = clubMemberRepository.findClubIdByIdCode(superiorUser.getIdCode());
        if (clubId != null) {
            return clubId;
        }
        return findFirstClub(superiorUser.getPidCode(),sec,eec);
    }

    private UserInfo findSuperiorUserOr(UserIdCode idCode, StarLevelEnum... starLevels) {
        if (idCode == null || starLevels == null) {
            return null;
        }
        UserInfo userInfo = userDocService.searchUserByIdCodeOrMobile(idCode, null);
        if (userInfo == null) {
            return null;
        }
        for (StarLevelEnum starLevel : starLevels) {
            if (starLevel.getCode().equals(userInfo.getStarLevel())) {
                return userInfo;
            }
        }
        if (userInfo.getPidCode() == null) {
            return null;
        }
        return findSuperiorUserOr(userInfo.getPidCode(),starLevels);
    }
}
